/**
 ******************************************************************************
 * @file    timer_Cap.h
 * @author  星辰
 * @version 1.0
 * @date    2022-8-20
 * @brief   输入捕获实验代码源文件。
 *          可用于测量脉冲宽度。
 ******************************************************************************
 */

#include <timer_Cap.h>

/**
 * @brief  TIM5输入捕获初始化
 * @note   输入捕获可用于测量脉冲宽度
 * @param  arr: TIM5 自动重装载值。
 *              此参数必须是介于 0x0000 和 0xFFFF 之间的数字
 * @param  psc: TIM5 预分频系数。
 *              此参数可以是 0x0000 和 0xFFFF 之间的数字
 * @retval None
 * @example 获取脉冲高电平持续时间
 *          usart1_init(115200);
 *          TIM5_Cap_init(0xffff, 71);
 *          while (1)
 *          {
 *              if (TIM5_CH1_CAPTURE_STA & 0X80) //成功捕获到了一次上升沿
 *              {
 *                  temp = TIM5_CH1_CAPTURE_STA & 0X3F;
 *                  temp *= 65536;                                //溢出时间总和
 *                  temp += TIM5_CH1_CAPTURE_VAL;                 //得到总的高电平时间
 *                  USART_printf(USART1, "HIGH:%d us\r\n", temp); //打印总的高点平时间
 *                  TIM5_CH1_CAPTURE_STA = 0;                     //开启下一次捕获
 *              }
 *          }
 */
void TIM5_Cap_init(u16 arr, u16 psc)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
    TIM_ICInitTypeDef TIM_ICInitStruct;
    NVIC_InitTypeDef NVIC_InitStruct;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能GPIOA
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);  // 使能TIM5

    // 初始化GPIOA（key1 的引脚）
    GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_IPD; // 下拉输入
    GPIO_InitStruct.GPIO_Pin   = GPIO_Pin_0;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStruct); // 初始化GPIOA PA0
    GPIO_ResetBits(GPIOA, GPIO_Pin_0);

    // 初始化 TIM5
    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;       // 设置时钟分割
    TIM_TimeBaseInitStruct.TIM_CounterMode   = TIM_CounterMode_Up; // 向上计数
    TIM_TimeBaseInitStruct.TIM_Period        = arr;                // 设置自动重装值
    TIM_TimeBaseInitStruct.TIM_Prescaler     = psc;                // 预分频器
    TIM_TimeBaseInit(TIM5, &TIM_TimeBaseInitStruct);

    // 初始化TIM5的输入捕获参数
    TIM_ICInitStruct.TIM_Channel     = TIM_Channel_1;            // 选择输入端（通道）
    TIM_ICInitStruct.TIM_ICFilter    = 0x00;                     // 配置输入滤波器，不滤波
    TIM_ICInitStruct.TIM_ICPolarity  = TIM_ICPolarity_Rising;    // 上升沿捕获
    TIM_ICInitStruct.TIM_ICPrescaler = TIM_ICPSC_DIV1;           // 配置输入分配，不分频
    TIM_ICInitStruct.TIM_ICSelection = TIM_ICSelection_DirectTI; // 映射到TI1上
    TIM_ICInit(TIM5, &TIM_ICInitStruct);

    // 初始化NVIC
    NVIC_InitStruct.NVIC_IRQChannel                   = TIM5_IRQn; // 中断类型
    NVIC_InitStruct.NVIC_IRQChannelCmd                = ENABLE;    // 使能
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;         // 抢占优先级
    NVIC_InitStruct.NVIC_IRQChannelSubPriority        = 0;         // 响应优先级
    NVIC_Init(&NVIC_InitStruct);

    // 使能更新中断，是为防止当脉冲宽度很长时，出现测量脉冲狂赌不准确的现象
    TIM_ITConfig(TIM5, TIM_IT_CC1 | TIM_IT_Update, ENABLE); // 使能更新中断和通道1捕获中断

    // 使能TIM5
    TIM_Cmd(TIM5, ENABLE);
}

/**
 * @brief TIM5_CH1_CAPTURE_STA 用于记录TIM5捕获状态。
 *        |    bit7     |      bit6      |           bit5~0           |
 *        | 捕获完成标志 | 捕获到高电平标志 | 捕获到高电平后TIM5溢出的次数 |
 */
u8 TIM5_CH1_CAPTURE_STA = 0;
u16 TIM5_CH1_CAPTURE_VAL; ///< 输入捕获值

/**
 * @brief  TIM5中断服务函数
 * @param  None
 * @retval None
 */
void TIM5_IRQHandler(void)
{
    // 还未成功捕获
    if ((TIM5_CH1_CAPTURE_STA & 0x80) == 0)
    {
        if (TIM_GetITStatus(TIM5, TIM_IT_Update) == SET)
        {
            if ((TIM5_CH1_CAPTURE_STA & 0x40) != 0) // 已经捕获到高电平
            {
                if ((TIM5_CH1_CAPTURE_STA & 0x3f) == 0x3f) // 高电平太长，超出最大捕获长度
                {
                    TIM5_CH1_CAPTURE_STA |= 0x80;  // 标记成功捕获一次
                    TIM5_CH1_CAPTURE_VAL = 0xffff; // 捕获的脉冲长度为最大（因为已经超出最大捕获长度）
                }
                else // 未超出最大捕获长度
                {
                    TIM5_CH1_CAPTURE_STA++;
                }
            }
        }

        if (TIM_GetITStatus(TIM5, TIM_IT_CC1) == SET)
        {
            if ((TIM5_CH1_CAPTURE_STA & 0x40) != 0) // 捕获到一个下降沿
            {
                TIM5_CH1_CAPTURE_STA |= 0x80;                     // 标记成功捕获一次高电平脉冲宽度
                TIM5_CH1_CAPTURE_VAL = TIM_GetCapture1(TIM5);     // 获取输入捕获1值
                TIM_OC1PolarityConfig(TIM5, TIM_OCPolarity_High); // 设置为上降沿捕获
            }
            else // 捕获到一个上升沿
            {
                TIM5_CH1_CAPTURE_STA = 0;                        // 清除捕获状态
                TIM5_CH1_CAPTURE_VAL = 0;                        // 清除捕获的脉冲时间
                TIM_SetCounter(TIM5, 0);                         // 清除计数器寄存器值(计数器值设置为0)
                TIM5_CH1_CAPTURE_STA |= 0x40;                    // 标记捕获到了上升沿
                TIM_OC1PolarityConfig(TIM5, TIM_OCPolarity_Low); // 设置为下降沿捕获
            }
        }
    }

    // 清除中断标志位
    TIM_ClearITPendingBit(TIM5, TIM_IT_Update | TIM_IT_CC1);
}
